コンテンツにスキップ

セッション

セッションは Agents SDK に 永続的なメモリレイヤー を提供します。Session インターフェイスを実装する任意のオブジェクトを Runner.run に渡すと、残りは SDK が処理します。セッションが存在する場合、ランナーは自動的に次の処理を行います:

  1. 以前に保存された会話アイテムを取得し、次のターンの先頭に追加します。
  2. 各実行の完了後に、新しいユーザー入力とアシスタント出力を永続化します。
  3. 新しいユーザーテキストでランナーを呼び出す場合でも、中断された RunState から再開する場合でも、以後のターンでセッションを利用できる状態に保ちます。

これにより、手動で toInputList() を呼び出したり、ターン間で履歴をつなぎ合わせたりする必要がなくなります。TypeScript SDK には、Conversations API 向けの OpenAIConversationsSession と、ローカル開発を想定した MemorySession の 2 つの実装が付属しています。どちらも Session インターフェイスを共有しているため、独自のストレージバックエンドを組み込めます。Conversations API 以外の参考実装として、examples/memory/ 配下のサンプルセッションバックエンド(Prisma、ファイルベースなど)を確認してください。OpenAI Responses モデルを使用する場合は、任意のセッションを OpenAIResponsesCompactionSession でラップすると、responses.compact によって保存済みの会話履歴を自動的に縮小できます。

ヒント: このページの OpenAIConversationsSession の例を実行するには、SDK が Conversations API を呼び出せるように、OPENAI_API_KEY 環境変数を設定します(または、セッションの構築時に apiKey を指定します)。

SDK にクライアント側メモリを管理させたい場合は、セッションを使用します。すでに conversationId または previousResponseId を使って OpenAI のサーバー管理状態を使用している場合は、通常、同じ会話履歴に対してセッションも必要ありません。


OpenAIConversationsSession を使用してメモリを Conversations API と同期するか、他の任意の Session 実装に差し替えます。

Conversations API をセッションメモリとして使用
import { Agent, OpenAIConversationsSession, run } from '@openai/agents';
const agent = new Agent({
name: 'TourGuide',
instructions: 'Answer with compact travel facts.',
});
// Any object that implements the Session interface works here. This example uses
// the built-in OpenAIConversationsSession, but you can swap in a custom Session.
const session = new OpenAIConversationsSession();
const firstTurn = await run(agent, 'What city is the Golden Gate Bridge in?', {
session,
});
console.log(firstTurn.finalOutput); // "San Francisco"
const secondTurn = await run(agent, 'What state is it in?', { session });
console.log(secondTurn.finalOutput); // "California"

同じセッションインスタンスを再利用すると、エージェントは毎ターン前に完全な会話履歴を受け取り、新しいアイテムは自動的に永続化されます。別の Session 実装に切り替える場合でも、他のコード変更は不要です。

ローカルデモ、テスト、またはプロセスローカルなチャット状態には、OpenAI と通信せずに同じインターフェイスを提供する MemorySession を使用できます:

ローカル状態に MemorySession を使用
import { Agent, MemorySession, run } from '@openai/agents';
const agent = new Agent({
name: 'TourGuide',
instructions: 'Answer with compact travel facts.',
});
const session = new MemorySession();
const result = await run(agent, 'What city is the Golden Gate Bridge in?', {
session,
});
console.log(result.finalOutput);

OpenAIConversationsSession コンストラクターオプション:

オプション注記
conversationIdstring遅延作成の代わりに既存の会話を再利用
clientOpenAI事前設定済みの OpenAI クライアントを渡す
apiKeystring内部 OpenAI クライアントの作成時に使用する API キー
baseURLstringOpenAI 互換エンドポイントのベース URL
organizationstringリクエスト用の OpenAI 組織 ID
projectstringリクエスト用の OpenAI プロジェクト ID

MemorySession コンストラクターオプション:

オプション注記
sessionIdstringログまたはテスト用の安定した識別子。デフォルトでは自動生成
initialItemsAgentInputItem[]既存の履歴でセッションを初期化
loggerLoggerデバッグ出力に使用するロガーを上書き

MemorySession はすべてをローカルプロセスのメモリに保存するため、プロセスが終了するとリセットされます。

セッションを構築する前に会話 ID を事前作成する必要がある場合は、 startOpenAIConversationsSession(client?) を使用し、返された ID を conversationId として渡します。


ランナーによるセッションの使用方法

Section titled “ランナーによるセッションの使用方法”
  • 各実行の前に セッション履歴を取得し、新しいターンの入力とマージして、結合されたリストをエージェントに渡します。
  • 非ストリーミング実行の後に session.addItems() への 1 回の呼び出しで、最新ターンの元のユーザー入力とモデル出力の両方を永続化します。
  • ストリーミング実行では ユーザー入力を先に書き込み、ターンが完了したらストリーミングされた出力を追加します。
  • RunResult.state から再開する場合 (承認やその他の中断のため)、同じ session を渡し続けます。再開されたターンは、入力を再準備せずにメモリに追加されます。

セッションはシンプルな CRUD ヘルパーを公開しているため、「元に戻す」「チャットをクリア」、監査機能を構築できます。

保存済みアイテムの読み取りと編集
import { OpenAIConversationsSession } from '@openai/agents';
import type { AgentInputItem } from '@openai/agents-core';
// Replace OpenAIConversationsSession with any other Session implementation that
// supports get/add/pop/clear if you store history elsewhere.
const session = new OpenAIConversationsSession({
conversationId: 'conv_123', // Resume an existing conversation if you have one.
});
const history = await session.getItems();
console.log(`Loaded ${history.length} prior items.`);
const followUp: AgentInputItem[] = [
{
type: 'message',
role: 'user',
content: [{ type: 'input_text', text: 'Let’s continue later.' }],
},
];
await session.addItems(followUp);
const undone = await session.popItem();
if (undone?.type === 'message') {
console.log(undone.role); // "user"
}
await session.clearSession();

session.getItems() は保存済みの AgentInputItem[] を返します。popItem() を呼び出すと最後のエントリを削除できます。これは、エージェントを再実行する前にユーザーの修正を反映する場合に便利です。


カスタムストレージとマージ動作

Section titled “カスタムストレージとマージ動作”

Session インターフェイスを実装して、Redis、DynamoDB、SQLite、またはその他のデータストアをメモリのバックエンドにできます。必要なのは 5 つの非同期メソッドだけです。

カスタムインメモリセッション実装
import { Agent, run } from '@openai/agents';
import { randomUUID } from '@openai/agents-core/_shims';
import { getLogger } from '@openai/agents-core';
import type { AgentInputItem, Session } from '@openai/agents-core';
/**
* Minimal example of a Session implementation; swap this class for any storage-backed version.
*/
export class CustomMemorySession implements Session {
private readonly sessionId: string;
private readonly logger: ReturnType<typeof getLogger>;
private items: AgentInputItem[];
constructor(
options: {
sessionId?: string;
initialItems?: AgentInputItem[];
logger?: ReturnType<typeof getLogger>;
} = {},
) {
this.sessionId = options.sessionId ?? randomUUID();
this.items = options.initialItems
? options.initialItems.map(cloneAgentItem)
: [];
this.logger = options.logger ?? getLogger('openai-agents:memory-session');
}
async getSessionId(): Promise<string> {
return this.sessionId;
}
async getItems(limit?: number): Promise<AgentInputItem[]> {
if (limit === undefined) {
const cloned = this.items.map(cloneAgentItem);
this.logger.debug(
`Getting items from memory session (${this.sessionId}): ${JSON.stringify(cloned)}`,
);
return cloned;
}
if (limit <= 0) {
return [];
}
const start = Math.max(this.items.length - limit, 0);
const items = this.items.slice(start).map(cloneAgentItem);
this.logger.debug(
`Getting items from memory session (${this.sessionId}): ${JSON.stringify(items)}`,
);
return items;
}
async addItems(items: AgentInputItem[]): Promise<void> {
if (items.length === 0) {
return;
}
const cloned = items.map(cloneAgentItem);
this.logger.debug(
`Adding items to memory session (${this.sessionId}): ${JSON.stringify(cloned)}`,
);
this.items = [...this.items, ...cloned];
}
async popItem(): Promise<AgentInputItem | undefined> {
if (this.items.length === 0) {
return undefined;
}
const item = this.items[this.items.length - 1];
const cloned = cloneAgentItem(item);
this.logger.debug(
`Popping item from memory session (${this.sessionId}): ${JSON.stringify(cloned)}`,
);
this.items = this.items.slice(0, -1);
return cloned;
}
async clearSession(): Promise<void> {
this.logger.debug(`Clearing memory session (${this.sessionId})`);
this.items = [];
}
}
function cloneAgentItem<T extends AgentInputItem>(item: T): T {
return structuredClone(item);
}
const agent = new Agent({
name: 'MemoryDemo',
instructions: 'Remember the running total.',
});
// Using the above custom memory session implementation here
const session = new CustomMemorySession({
sessionId: 'session-123-4567',
});
const first = await run(agent, 'Add 3 to the total.', { session });
console.log(first.finalOutput);
const second = await run(agent, 'Add 4 more.', { session });
console.log(second.finalOutput);

カスタムセッションを使うと、保持ポリシーの適用、暗号化の追加、または永続化前に各会話ターンへメタデータを付与できます。


履歴と新規アイテムのマージ方法の制御

Section titled “履歴と新規アイテムのマージ方法の制御”

実行入力として AgentInputItem の配列を渡す場合は、sessionInputCallback を指定して、保存済み履歴と決定的にマージします。ランナーは既存の履歴を読み込み、モデル呼び出しの前に コールバックを呼び出し、返された配列をそのターンの完全な入力としてモデルに渡します。このフックは、古いアイテムの切り詰め、ツール結果の重複排除、またはモデルに見せたいコンテキストだけを強調する用途に最適です。

sessionInputCallback による履歴の切り詰め
import { Agent, OpenAIConversationsSession, run } from '@openai/agents';
import type { AgentInputItem } from '@openai/agents-core';
const agent = new Agent({
name: 'Planner',
instructions: 'Track outstanding tasks before responding.',
});
// Any Session implementation can be passed here; customize storage as needed.
const session = new OpenAIConversationsSession();
const todoUpdate: AgentInputItem[] = [
{
type: 'message',
role: 'user',
content: [
{ type: 'input_text', text: 'Add booking a hotel to my todo list.' },
],
},
];
await run(agent, todoUpdate, {
session,
// function that combines session history with new input items before the model call
sessionInputCallback: (history, newItems) => {
const recentHistory = history.slice(-8);
return [...recentHistory, ...newItems];
},
});

文字列入力の場合、ランナーは履歴を自動的にマージするため、このコールバックは任意です。このコールバックはターン入力がすでにアイテム配列である場合にのみ実行されます。

conversationId または previousResponseId も使用している場合は、コールバック結果に現在のターンから少なくとも 1 つの新規アイテムを残してください。これらのサーバー管理 API は、現在のターンの差分に依存します。コールバックがすべての新規アイテムを削除した場合、SDK は空の差分を送信する代わりに元の新規入力を復元し、警告をログに記録します。


Human in the loop (人間の介入) フローでは、承認を待つために実行を一時停止することがよくあります:

同じセッションで実行を再開
import { Agent, MemorySession, Runner } from '@openai/agents';
const agent = new Agent({
name: 'Trip Planner',
instructions: 'Plan trips and ask for approval before booking anything.',
});
const runner = new Runner();
const session = new MemorySession();
const result = await runner.run(agent, 'Search the itinerary', {
session,
});
if (result.interruptions?.length) {
// ... collect user feedback, then resume the agent in a later turn.
for (const interruption of result.interruptions) {
result.state.approve(interruption);
}
const continuation = await runner.run(agent, result.state, { session });
console.log(continuation.finalOutput);
}

以前の RunState から再開すると、新しいターンは同じメモリレコードに追加され、単一の会話履歴が保持されます。Human-in-the-loop(HITL)フローは完全に互換性を保ちます。承認チェックポイントは引き続き RunState を介して往復し、セッションは会話履歴を完全な状態に保ちます。


OpenAIResponsesCompactionSession は任意の Session をデコレートし、OpenAI Responses API を使用して、長い保存済み履歴をより短い等価な会話アイテムのリストに置き換えます。保存された各ターンの後、ランナーは最新の responseIdrunCompaction に渡し、判断フックが true を返すと responses.compact を呼び出します。compactionMode に応じて、リクエストは最新の Responses API チェーン、またはセッションの現在のアイテムのどちらかから構築されます。デフォルトのトリガーは、少なくとも 10 個の非ユーザーアイテムが蓄積された時点で圧縮を実行します。トークン数やカスタムヒューリスティックに基づいて判断したい場合は、shouldTriggerCompaction を上書きします。圧縮が返ると、デコレーターは基盤となるセッションをクリアし、縮小後のアイテムリストで書き換えます。そのため、異なるサーバー管理履歴フローを使用する OpenAIConversationsSession との併用は避けてください。

OpenAIResponsesCompactionSession によるセッションのデコレート
import {
Agent,
MemorySession,
OpenAIResponsesCompactionSession,
run,
} from '@openai/agents';
const agent = new Agent({
name: 'Support',
instructions: 'Answer briefly and keep track of prior context.',
model: 'gpt-5.4',
});
// Wrap any Session to trigger responses.compact once history grows beyond your threshold.
const session = new OpenAIResponsesCompactionSession({
// You can pass any Session implementation except OpenAIConversationsSession
underlyingSession: new MemorySession(),
// (optional) The model used for calling responses.compact API
model: 'gpt-5.4',
// (optional) your custom logic here
shouldTriggerCompaction: ({ compactionCandidateItems }) => {
return compactionCandidateItems.length >= 12;
},
});
await run(agent, 'Summarize order #8472 in one sentence.', { session });
await run(agent, 'Remind me of the shipping address.', { session });
// Compaction runs automatically after each persisted turn. You can also force it manually.
await session.runCompaction({ force: true });

OpenAIResponsesCompactionSession コンストラクターオプション:

オプション注記
clientOpenAIresponses.compact に使用する OpenAI クライアント
underlyingSessionSession圧縮後のアイテムでクリアおよび書き換える基盤セッションストア。デモ用のインメモリセッションがデフォルトであり、OpenAIConversationsSession であってはなりません
modelOpenAI.ResponsesModel圧縮リクエストに使用するモデル。SDK の現在のデフォルト OpenAI モデルがデフォルト
compactionMode'auto' | 'previous_response_id' | 'input'圧縮でサーバーレスポンスの連鎖を使用するか、ローカル入力アイテムを使用するかを制御
shouldTriggerCompaction(context) => boolean | Promise<boolean>responseIdcompactionMode、候補アイテム、現在のセッションアイテムに基づくカスタムトリガーフック

compactionMode: 'previous_response_id' は、すでに Responses API のレスポンス ID でターンを連鎖している場合に便利です。compactionMode: 'input' は、代わりに現在のセッションアイテムから圧縮リクエストを再構築します。これは、レスポンスチェーンを利用できない場合や、基盤セッションの内容を信頼できる情報源にしたい場合に役立ちます。

runCompaction(args) オプション:

オプション注記
responseIdstringprevious_response_id モード用の最新 Responses API レスポンス ID
compactionMode'auto' | 'previous_response_id' | 'input'設定済みモードに対する呼び出しごとの任意の上書き
storeboolean最後の実行がサーバー状態を保存したかどうかを示す
forcebooleanshouldTriggerCompaction をバイパスして即座に圧縮

低レイテンシーストリーミング向けの手動圧縮

Section titled “低レイテンシーストリーミング向けの手動圧縮”

圧縮では基盤となるセッションをクリアして書き換えるため、SDK はストリーミング実行を解決する前に完了を待ちます。圧縮が重い場合、最後の出力トークンの後でも result.completed が数秒間 pending のままになることがあります。低レイテンシーのストリーミングや、よりすばやいターン進行のためには、自動圧縮を無効にし、ターン間(またはアイドル時間中)に自分で runCompaction を呼び出します。

自動圧縮を無効化し、ターン間で圧縮
import {
Agent,
MemorySession,
OpenAIResponsesCompactionSession,
run,
} from '@openai/agents';
const agent = new Agent({
name: 'Support',
instructions: 'Answer briefly and keep track of prior context.',
model: 'gpt-5.4',
});
// Disable auto-compaction to avoid delaying stream completion.
const session = new OpenAIResponsesCompactionSession({
underlyingSession: new MemorySession(),
shouldTriggerCompaction: () => false,
});
const result = await run(agent, 'Share the latest ticket update.', {
session,
stream: true,
});
// Wait for the streaming run to finish before compacting.
await result.completed;
// Choose force based on your own thresholds or heuristics, between turns or during idle time.
await session.runCompaction({ force: true });

アーカイブまたはハンドオフの前に履歴を縮小するため、いつでも runCompaction({ force: true }) を呼び出せます。圧縮判断をトレースするには、DEBUG=openai-agents:openai:compaction でデバッグログを有効にします。