opentag平台提及到本地代理
§ · Nested detail page

Context packet 与协议收敛 深度解析

本页只展开一个模块,把导入契约、核心实现、流程和失败模式拆成可回溯行号。

§ 00 · IMPORT CHAIN

导入链与契约

入口代码说明该模块接受什么输入、输出什么结构,以及它依赖哪些相邻模块。

▸入口片段

packages/core/src/protocol.ts · L124-159TypeScript
 124function classifyContextPointer(pointer: ContextPointer): ClassifiedContextPointer {
 125  if (pointer.kind === "text") {
 126    return { pointer, classification: "primary_evidence", reason: "Original user-authored text is primary evidence." };
 127  }
 128  if (["issue", "pull_request", "comment", "thread", "message"].includes(pointer.kind)) {
 129    return { pointer, classification: "primary_evidence", reason: `${contextPointerLabel(pointer)} is directly attached to the invocation.` };
 130  }
 131  if (["repo", "file", "url"].includes(pointer.kind)) {
 132    return { pointer, classification: "supporting_context", reason: `${contextPointerLabel(pointer)} supports execution but is not itself the request.` };
 133  }
 134  return { pointer, classification: "supporting_context", reason: "Pointer is relevant context." };
 135}
 136
 137export function collectContextPointers(event: OpenTagEvent): ContextPointer[] {
 138  return event.context;
 139}
 140
 141export function classifyContextPointers(pointers: ContextPointer[]): ClassifiedContextPointer[] {
 142  return pointers.map((pointer) => classifyContextPointer(pointer));
 143}
 144
 145export function filterClassifiedContextPointers(classified: ClassifiedContextPointer[]): ClassifiedContextPointer[] {
 146  return classified.filter((entry) => entry.classification !== "background_noise" && entry.classification !== "sensitive_material");
 147}
 148
 149type ContextPacketFact = { text: string; sourceUri?: string; source?: ContextPointer; confidence?: ContextPacketFactConfidence };
 150
 151function metadataString(event: OpenTagEvent, key: string): string | undefined {
 152  const value = event.metadata[key];
 153  return typeof value === "string" && value.length > 0 ? value : undefined;
 154}
 155
 156function metadataStringArray(event: OpenTagEvent, key: string): string[] {
 157  const value = event.metadata[key];
 158  if (!Array.isArray(value)) return [];
 159  return value.filter((item): item is string => typeof item === "string" && item.length > 0);

源码索引:packages/core/src/protocol.ts:124 · packages/core/src/protocol.ts:125 · packages/core/src/protocol.ts:126 · packages/core/src/protocol.ts:127 · packages/core/src/protocol.ts:128 · packages/core/src/protocol.ts:129 · packages/core/src/protocol.ts:130 · packages/core/src/protocol.ts:131 · packages/core/src/protocol.ts:132 · packages/core/src/protocol.ts:133 · packages/core/src/protocol.ts:134 · packages/core/src/protocol.ts:135 · packages/core/src/protocol.ts:136 · packages/core/src/protocol.ts:137 · packages/core/src/protocol.ts:138 · packages/core/src/protocol.ts:139 · packages/core/src/protocol.ts:140 · packages/core/src/protocol.ts:141 · packages/core/src/protocol.ts:142 · packages/core/src/protocol.ts:143 · packages/core/src/protocol.ts:144 · packages/core/src/protocol.ts:145 · packages/core/src/protocol.ts:146 · packages/core/src/protocol.ts:147 · packages/core/src/protocol.ts:148 · packages/core/src/protocol.ts:149 · packages/core/src/protocol.ts:150 · packages/core/src/protocol.ts:151 · packages/core/src/protocol.ts:152 · packages/core/src/protocol.ts:153 · packages/core/src/protocol.ts:154 · packages/core/src/protocol.ts:155 · packages/core/src/protocol.ts:156 · packages/core/src/protocol.ts:157 · packages/core/src/protocol.ts:158 · packages/core/src/protocol.ts:159 · packages/core/src/protocol.ts:160 · packages/core/src/protocol.ts:161 · packages/core/src/protocol.ts:162 · packages/core/src/protocol.ts:163 · packages/core/src/protocol.ts:164 · packages/core/src/protocol.ts:165 · packages/core/src/protocol.ts:166 · packages/core/src/protocol.ts:167 · packages/core/src/protocol.ts:168

§ 01 · CORE IMPL

核心实现,逐段拆

▸中段状态转换

这一段通常体现最关键的状态转换:解析、选择、打分、写入或安全检查。

packages/core/src/protocol.ts · L160-199TypeScript
 160}
 161
 162function preserveActionLoopFacts(event: OpenTagEvent): ContextPacketFact[] {
 163  const facts: ContextPacketFact[] = [];
 164  const threadActionVerb = metadataString(event, "threadActionVerb");
 165  const parentRunId = metadataString(event, "parentRunId");
 166  const sourceProposalId = metadataString(event, "sourceProposalId");
 167  const approvalDecisionId = metadataString(event, "approvalDecisionId");
 168  const sourceApplyPlanId = metadataString(event, "sourceApplyPlanId");
 169  const previousRunSummary = metadataString(event, "previousRunSummary");
 170  const fallbackReason = metadataString(event, "fallbackReason");
 171  const selectedIntentIds = metadataStringArray(event, "selectedIntentIds");
 172
 173  if (threadActionVerb) facts.push({ text: `Action loop thread action: ${threadActionVerb}`, confidence: "observed" });
 174  if (parentRunId) facts.push({ text: `Action loop parent run: ${parentRunId}`, confidence: "observed" });
 175  if (sourceProposalId) facts.push({ text: `Action loop proposal: ${sourceProposalId}`, confidence: "observed" });
 176  if (approvalDecisionId) facts.push({ text: `Action loop approval decision: ${approvalDecisionId}`, confidence: "observed" });
 177  if (sourceApplyPlanId) facts.push({ text: `Action loop apply plan: ${sourceApplyPlanId}`, confidence: "observed" });
 178  if (selectedIntentIds.length > 0) facts.push({ text: `Action loop selected intents: ${selectedIntentIds.join(", ")}`, confidence: "observed" });
 179  if (previousRunSummary) facts.push({ text: `Action loop previous result: ${previousRunSummary}`, confidence: "observed" });
 180  if (fallbackReason) facts.push({ text: `Action loop fallback reason: ${fallbackReason}`, confidence: "observed" });
 181
 182  return facts;
 183}
 184
 185export function preserveContextFacts(event: OpenTagEvent, classified: ClassifiedContextPointer[]): ContextPacketFact[] {
 186  const sourceUri = classified[0]?.pointer.uri;
 187  return [
 188    {
 189      text: `Requested intent: ${event.command.intent}`,
 190      ...(sourceUri ? { sourceUri } : {}),
 191      ...(classified[0]?.pointer ? { source: classified[0].pointer } : {}),
 192      confidence: "observed"
 193    },
 194    ...preserveActionLoopFacts(event),
 195    ...classified.map((entry) => ({
 196      text: `${entry.classification}: ${contextPointerLabel(entry.pointer)}`,
 197      sourceUri: entry.pointer.uri,
 198      source: entry.pointer,
 199      confidence: "observed" as const

▸末段收束

收束段决定失败是否显式返回、结果是否稳定落盘,以及调用者能否继续恢复。

packages/core/src/protocol.ts · L185-220TypeScript
 185export function preserveContextFacts(event: OpenTagEvent, classified: ClassifiedContextPointer[]): ContextPacketFact[] {
 186  const sourceUri = classified[0]?.pointer.uri;
 187  return [
 188    {
 189      text: `Requested intent: ${event.command.intent}`,
 190      ...(sourceUri ? { sourceUri } : {}),
 191      ...(classified[0]?.pointer ? { source: classified[0].pointer } : {}),
 192      confidence: "observed"
 193    },
 194    ...preserveActionLoopFacts(event),
 195    ...classified.map((entry) => ({
 196      text: `${entry.classification}: ${contextPointerLabel(entry.pointer)}`,
 197      sourceUri: entry.pointer.uri,
 198      source: entry.pointer,
 199      confidence: "observed" as const
 200    }))
 201  ];
 202}
 203
 204export function summarizeContextPacket(event: OpenTagEvent): string {
 205  // A whitespace-only rawText is functionally empty, so fall back to the derived
 206  // request label rather than emitting a blank summary.
 207  return event.command.rawText.trim() || `OpenTag ${event.command.intent} request`;
 208}
 209
 210export function budgetContextPointers(classified: ClassifiedContextPointer[], budgetTokens?: number): ClassifiedContextPointer[] {
 211  if (!budgetTokens) return classified;
 212  const maxPointers = Math.max(1, Math.floor(budgetTokens / 500));
 213  return classified.slice(0, maxPointers);
 214}
 215
 216export function assembleContextPacketFromEvent(
 217  event: OpenTagEvent,
 218  emittedAt = event.receivedAt,
 219  options: ContextPacketAssemblyOptions = {}
 220): ContextPacket {
§ 02 · KEY FLOW

关键流程

▸流程拆解

input → normalize → validate → output
failure → explicit fallback / error record → caller decision

如果后续改动触碰这些行,主页面对应的风险判断也要重跑。

§ 03 · EDGE CASES

边界 / 失败模式

▸边界列表

  • 空输入或缺失字段必须被显式处理。
  • 外部命令、模型调用或文件写入失败不能覆盖原始上下文。
  • 路径别名仅用于索引兼容;实际源码位置见每个代码块的 repo 标注。
Sub-page · 2026-06-29Source · amplifthq/opentag↑ opentag 主页面