コンテンツにスキップ

セッション

セッションは Agents SDK による永続メモリ層を提供します。Session インターフェースを実装した任意のオブジェクトを Runner.run に渡すだけで、残りは SDK が処理します。セッションがある場合、runner は自動的に次を行います。

  1. 以前に保存された会話アイテムを取得し、次のターンの先頭に付与
  2. 各実行完了後に新しいユーザー入力とアシスタント出力を永続化
  3. 新しいユーザーのテキストで runner を呼び出す場合も、中断された RunState から再開する場合も、今後のターンのためにセッションを保持

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

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


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 実装に切り替えても、他のコード変更は不要です。

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

OptionTypeNotes
conversationIdstring既存の会話を再利用し、遅延作成を行わない
clientOpenAI事前設定済みの OpenAI クライアントを渡す
apiKeystring内部の OpenAI クライアントを作成する際に使用する API キー
baseURLstringOpenAI 互換エンドポイントのベース URL
organizationstringリクエスト用の OpenAI 組織 ID
projectstringリクエスト用の OpenAI プロジェクト ID

runner によるセッションの利用方法

Section titled “runner によるセッションの利用方法”
  • 各実行前 にセッション履歴を取得し、新しいターンの入力とマージして、その結合リストをエージェントに渡す
  • 非ストリーミング実行後session.addItems() の一度の呼び出しで、直近ターンの元のユーザー入力とモデル出力の両方を永続化
  • ストリーミング実行時 は先にユーザー入力を書き込み、ターン完了後にストリーム出力を追記
  • 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() を呼び出すと最後のエントリを削除できます。エージェントを再実行する前のユーザー修正に便利です。


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 を指定して、保存済み履歴とのマージを決定的に行えます。runner は既存履歴をロードし、モデル呼び出し前に コールバックを呼び出し、返された配列をそのターンの完全な入力としてモデルに渡します。このフックは、古いアイテムの切り詰め、ツール結果の重複排除、モデルに見せたいコンテキストのみの強調に最適です。

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];
},
});

文字列入力の場合、runner は履歴を自動的にマージするため、コールバックは任意です。


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

const result = await runner.run(agent, 'Search the itinerary', {
session,
stream: true,
});
if (result.requiresApproval) {
// ... collect user feedback, then resume the agent in a later turn
const continuation = await runner.run(agent, result.state, { session });
console.log(continuation.finalOutput);
}

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


OpenAI Responses の履歴を自動的に縮約

Section titled “OpenAI Responses の履歴を自動的に縮約”

OpenAIResponsesCompactionSession は任意の Session をデコレートし、OpenAI Responses API に依存してトランスクリプトを短く保ちます。各ターンを永続化した後、runner は最新の responseIdrunCompaction に渡します。これは、意思決定フックが true を返したときに responses.compact を呼び出します。デフォルトのトリガーは、ユーザー以外のアイテムが少なくとも 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.2',
});
// 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.2',
// (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 のコンストラクターオプション:

OptionTypeNotes
clientOpenAIresponses.compact に使用する OpenAI クライアント
underlyingSessionSession縮約済みアイテムでクリア/書き換えを行うバックエンドのセッションストア(OpenAIConversationsSession は不可)
modelOpenAI.ResponsesModel縮約リクエストに使用するモデル
compactionMode'auto' | 'previous_response_id' | 'input'縮約でサーバーのレスポンスチェーンを使うかローカル入力アイテムを使うかの制御
shouldTriggerCompaction(context) => boolean | Promise<boolean>responseIdcompactionMode、候補アイテム、現在のセッションアイテムに基づくカスタムトリガーフック

runCompaction(args) のオプション:

OptionTypeNotes
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.2',
});
// 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 を有効にすると、縮約の判断をトレースできます。