@ai-sdk/harness-opencode 1.0.103 → 1.0.105

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -342,8 +342,15 @@ function buildProviderConfig(
342
342
  apiKey: procEnv.AI_GATEWAY_API_KEY,
343
343
  baseURL: toOpenCodeGatewayBaseUrl(procEnv.AI_GATEWAY_BASE_URL),
344
344
  ...(HARNESS_CLIENT_APP
345
- ? { headers: { 'x-client-app': HARNESS_CLIENT_APP } }
346
- : {}),
345
+ ? {
346
+ headers: {
347
+ ...start.headers,
348
+ 'x-client-app': HARNESS_CLIENT_APP,
349
+ },
350
+ }
351
+ : start.headers
352
+ ? { headers: start.headers }
353
+ : {}),
347
354
  },
348
355
  ...(modelID
349
356
  ? {
@@ -369,6 +376,7 @@ function buildProviderConfig(
369
376
  ...(procEnv.OPENAI_BASE_URL
370
377
  ? { baseURL: procEnv.OPENAI_BASE_URL }
371
378
  : {}),
379
+ ...(start.headers ? { headers: start.headers } : {}),
372
380
  ...parseOpenAIQueryParams(),
373
381
  },
374
382
  ...(modelID
@@ -400,6 +408,7 @@ function buildProviderConfig(
400
408
  ...(procEnv.ANTHROPIC_BASE_URL
401
409
  ? { baseURL: procEnv.ANTHROPIC_BASE_URL }
402
410
  : {}),
411
+ ...(start.headers ? { headers: start.headers } : {}),
403
412
  },
404
413
  },
405
414
  };
@@ -422,6 +431,7 @@ function buildProviderConfig(
422
431
  ...(procEnv.OPENAI_PROJECT
423
432
  ? { project: procEnv.OPENAI_PROJECT }
424
433
  : {}),
434
+ ...(start.headers ? { headers: start.headers } : {}),
425
435
  ...parseOpenAIQueryParams(),
426
436
  },
427
437
  },
@@ -18,6 +18,7 @@ export const startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
18
18
  resumeSessionId: z.string().optional(),
19
19
  openCodeConfig: z.record(z.string(), z.unknown()).optional(),
20
20
  mcpServers: z.record(z.string(), z.unknown()).optional(),
21
+ headers: z.record(z.string(), z.string()).optional(),
21
22
  });
22
23
 
23
24
  export type StartMessage = z.infer<typeof startMessageSchema>;
@@ -14,6 +14,7 @@ import {
14
14
  type HarnessV1PermissionMode,
15
15
  type HarnessV1Prompt,
16
16
  type HarnessV1PromptControl,
17
+ type HarnessV1ResponseFormat,
17
18
  type HarnessV1PortEndpoint,
18
19
  type HarnessV1ResumeSessionState,
19
20
  type HarnessV1Session,
@@ -39,7 +40,7 @@ import {
39
40
  warnCredentialBrokeringUnavailable,
40
41
  waitForBridgeReady,
41
42
  withBridgeToken,
42
- writeSkills as writeHarnessSkills,
43
+ writeSkills,
43
44
  type WriteSkillsResult,
44
45
  } from '@ai-sdk/harness/utils';
45
46
  import {
@@ -412,6 +413,7 @@ export function createOpenCode(
412
413
  reasoningVariant: settings.reasoningVariant,
413
414
  openCodeConfig: settings.openCodeConfig,
414
415
  mcpServers: settings.mcpServers,
416
+ headers: startOpts.headers,
415
417
  openCodeSessionId: resumeSessionId,
416
418
  isResume: true,
417
419
  seedResumeSessionOnFirstPrompt: false,
@@ -569,6 +571,7 @@ export function createOpenCode(
569
571
  reasoningVariant: settings.reasoningVariant,
570
572
  openCodeConfig: settings.openCodeConfig,
571
573
  mcpServers: settings.mcpServers,
574
+ headers: startOpts.headers,
572
575
  openCodeSessionId: resumeSessionId,
573
576
  isResume: respawnStrategy !== undefined,
574
577
  seedResumeSessionOnFirstPrompt: respawnStrategy !== undefined,
@@ -653,30 +656,6 @@ async function resolveBridgeEndpoint({
653
656
  });
654
657
  }
655
658
 
656
- async function writeOpenCodeSkills({
657
- sandbox,
658
- skills,
659
- homeDir,
660
- abortSignal,
661
- }: {
662
- sandbox: SandboxSession;
663
- skills: ReadonlyArray<HarnessV1Skill>;
664
- homeDir: string;
665
- abortSignal?: AbortSignal;
666
- }): Promise<WriteSkillsResult> {
667
- const skillsDir = path.posix.join(homeDir, '.agents', 'skills');
668
- return writeHarnessSkills({
669
- sandbox,
670
- rootDir: skillsDir,
671
- skills,
672
- abortSignal,
673
- invalidSkillNameMessage: ({ name }) =>
674
- `Invalid OpenCode skill name: ${name}`,
675
- invalidSkillFilePathMessage: ({ skillName, filePath }) =>
676
- `Invalid OpenCode skill file path for ${skillName}: ${filePath}`,
677
- });
678
- }
679
-
680
659
  function openWebSocket({
681
660
  endpoint,
682
661
  helloTimeoutMs,
@@ -786,6 +765,7 @@ function createSession({
786
765
  reasoningVariant,
787
766
  openCodeConfig,
788
767
  mcpServers,
768
+ headers,
789
769
  openCodeSessionId,
790
770
  isResume,
791
771
  seedResumeSessionOnFirstPrompt,
@@ -809,6 +789,7 @@ function createSession({
809
789
  reasoningVariant: string | undefined;
810
790
  openCodeConfig: Record<string, unknown> | undefined;
811
791
  mcpServers: Record<string, unknown> | undefined;
792
+ headers: Readonly<Record<string, string>> | undefined;
812
793
  openCodeSessionId: string | undefined;
813
794
  isResume: boolean;
814
795
  seedResumeSessionOnFirstPrompt: boolean;
@@ -990,6 +971,7 @@ function createSession({
990
971
  ...(reasoningVariant ? { variant: reasoningVariant } : {}),
991
972
  ...(openCodeConfig == null ? {} : { openCodeConfig }),
992
973
  ...(mcpServers == null ? {} : { mcpServers }),
974
+ ...(headers == null ? {} : { headers }),
993
975
  ...(permissionMode ? { permissionMode } : {}),
994
976
  ...(builtinToolFiltering ? { builtinToolFiltering } : {}),
995
977
  ...(pendingResumeSessionId
@@ -1000,30 +982,48 @@ function createSession({
1000
982
  ...(debug ? { debug } : {}),
1001
983
  });
1002
984
 
985
+ const prepareTurn = async (opts: {
986
+ responseFormat?: HarnessV1ResponseFormat;
987
+ skills: ReadonlyArray<HarnessV1Skill>;
988
+ emit: (event: HarnessV1StreamPart) => void;
989
+ abortSignal?: AbortSignal;
990
+ }): Promise<{
991
+ control: HarnessV1PromptControl;
992
+ skillWriteResult: WriteSkillsResult;
993
+ }> => {
994
+ if (
995
+ opts.responseFormat?.type === 'json' &&
996
+ opts.responseFormat.schema == null
997
+ ) {
998
+ throw new HarnessCapabilityUnsupportedError({
999
+ message:
1000
+ "Harness 'opencode' requires a JSON schema for structured output.",
1001
+ harnessId: 'opencode',
1002
+ });
1003
+ }
1004
+ const skillWriteResult = await writeSkills({
1005
+ sandbox,
1006
+ homePath: sandboxHomeDir,
1007
+ skillsDir: '.agents/skills',
1008
+ skills: opts.skills,
1009
+ abortSignal: opts.abortSignal,
1010
+ invalidSkillNameMessage: ({ name }) =>
1011
+ `Invalid OpenCode skill name: ${name}`,
1012
+ invalidSkillFilePathMessage: ({ skillName, filePath }) =>
1013
+ `Invalid OpenCode skill file path for ${skillName}: ${filePath}`,
1014
+ });
1015
+ const control = wireTurn({
1016
+ emit: opts.emit,
1017
+ abortSignal: opts.abortSignal,
1018
+ });
1019
+ return { control, skillWriteResult };
1020
+ };
1021
+
1003
1022
  return {
1004
1023
  sessionId,
1005
1024
  isResume,
1006
1025
  doPromptTurn: async promptOpts => {
1007
- if (
1008
- promptOpts.responseFormat?.type === 'json' &&
1009
- promptOpts.responseFormat.schema == null
1010
- ) {
1011
- throw new HarnessCapabilityUnsupportedError({
1012
- message:
1013
- "Harness 'opencode' requires a JSON schema for structured output.",
1014
- harnessId: 'opencode',
1015
- });
1016
- }
1017
- const skillWriteResult = await writeOpenCodeSkills({
1018
- sandbox,
1019
- skills: promptOpts.skills,
1020
- homeDir: sandboxHomeDir,
1021
- abortSignal: promptOpts.abortSignal,
1022
- });
1023
- const control = wireTurn({
1024
- emit: promptOpts.emit,
1025
- abortSignal: promptOpts.abortSignal,
1026
- });
1026
+ const { control, skillWriteResult } = await prepareTurn(promptOpts);
1027
1027
  const turnModel = promptOpts.model ?? selectedModel;
1028
1028
  if (turnModel) selectedModel = turnModel;
1029
1029
  channel.send({
@@ -1048,26 +1048,7 @@ function createSession({
1048
1048
  return control;
1049
1049
  },
1050
1050
  doContinueTurn: async continueOpts => {
1051
- if (
1052
- continueOpts.responseFormat?.type === 'json' &&
1053
- continueOpts.responseFormat.schema == null
1054
- ) {
1055
- throw new HarnessCapabilityUnsupportedError({
1056
- message:
1057
- "Harness 'opencode' requires a JSON schema for structured output.",
1058
- harnessId: 'opencode',
1059
- });
1060
- }
1061
- const skillWriteResult = await writeOpenCodeSkills({
1062
- sandbox,
1063
- skills: continueOpts.skills,
1064
- homeDir: sandboxHomeDir,
1065
- abortSignal: continueOpts.abortSignal,
1066
- });
1067
- const control = wireTurn({
1068
- emit: continueOpts.emit,
1069
- abortSignal: continueOpts.abortSignal,
1070
- });
1051
+ const { control, skillWriteResult } = await prepareTurn(continueOpts);
1071
1052
  if (rerunContinue) {
1072
1053
  const turnModel = continueOpts.model ?? selectedModel;
1073
1054
  if (turnModel) selectedModel = turnModel;
@@ -1116,6 +1097,7 @@ function createSession({
1116
1097
  debug,
1117
1098
  openCodeConfig,
1118
1099
  mcpServers,
1100
+ headers,
1119
1101
  resumeSessionId: latestOpenCodeSessionId,
1120
1102
  onCompaction: part => pendingCompactionParts.push(part),
1121
1103
  });
@@ -1289,6 +1271,7 @@ async function runCompactOperation({
1289
1271
  debug,
1290
1272
  openCodeConfig,
1291
1273
  mcpServers,
1274
+ headers,
1292
1275
  resumeSessionId,
1293
1276
  onCompaction,
1294
1277
  }: {
@@ -1299,6 +1282,7 @@ async function runCompactOperation({
1299
1282
  debug: HarnessV1DebugConfig | undefined;
1300
1283
  openCodeConfig: Record<string, unknown> | undefined;
1301
1284
  mcpServers: Record<string, unknown> | undefined;
1285
+ headers: Readonly<Record<string, string>> | undefined;
1302
1286
  resumeSessionId: string | undefined;
1303
1287
  onCompaction: (part: HarnessV1StreamPart) => void;
1304
1288
  }): Promise<void> {
@@ -1328,6 +1312,7 @@ async function runCompactOperation({
1328
1312
  provider,
1329
1313
  ...(openCodeConfig == null ? {} : { openCodeConfig }),
1330
1314
  ...(mcpServers == null ? {} : { mcpServers }),
1315
+ ...(headers == null ? {} : { headers }),
1331
1316
  ...(permissionMode ? { permissionMode } : {}),
1332
1317
  ...(resumeSessionId ? { resumeSessionId } : {}),
1333
1318
  ...(debug ? { debug } : {}),